home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / gnulib / libsrc98.zoo / stat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-24  |  9.0 KB  |  368 lines

  1. /*
  2.  * stat, fstat, lstat emulation for TOS
  3.  *
  4.  * written by Eric R. Smith and Jwahar Bammi, based on the original
  5.  * from the old GCC library (which original was copyright 1988
  6.  * Memorial University).
  7.  */
  8.  
  9. #include    <assert.h>
  10. #include    <stdio.h>
  11. #include    <types.h>
  12. #include    <stat.h>
  13. #include    <ctype.h>
  14. #include    <errno.h>
  15. #include    <osbind.h>
  16. #include    <unistd.h>
  17. #include    <support.h>
  18. #include    <string.h>
  19. #include    <dirent.h>
  20. #include    <device.h>
  21. #include    "symdir.h"
  22. #include    <time.h>
  23. #include    "lib.h"
  24. #include    <memory.h>
  25.  
  26. #ifndef NAME_MAX
  27. #  include <limits.h>
  28. #endif
  29.  
  30. #ifndef _LIB_NAME_MAX
  31. #  define _LIB_NAME_MAX NAME_MAX
  32. #endif
  33.  
  34.  
  35. ino_t    __inode = 32;        /* used in readdir also */
  36. int    _x_Bit_set_in_stat = 0;    /* default 0, need change in emacs:sysdep.c */
  37.  
  38. DIR *__opendir_chain = 0;    /* chain of open directories from opendir */
  39.  
  40. /* date for files (like root directories) that don't have one */
  41. #define OLDDATE _unixtime(0,0)
  42.  
  43. /*
  44.  * check file cache for the file whose canonical (_unx2dos) name is fullname.
  45.  * this is only valid for TOS files, i.e. files that are NOT symbolic
  46.  * links. If file is not found in cache, use Fsfirst to look it up.
  47.  * All open directories (via opendir) are cached (we don't lose much by
  48.  * doing this, and it's a good heuristic for which files are going to
  49.  * need stat() in the near future; plus, opendir did Fsfirst()/Fsnext()
  50.  * already. Programs like "ls" should win big time.
  51.  *
  52.  * BUG/FEATURE: if the _lHIDE flag is set, opendir() never records the
  53.  * existence of .dir, and so stat() in an open directory won't find it.
  54.  */
  55.  
  56. struct dirent *
  57. _do_stat(fullname)
  58. char *fullname;
  59. {
  60.     char path[FILENAME_MAX], name[_LIB_NAME_MAX], *tmp;
  61.     DIR *dir;
  62.     struct dirent *d;
  63.     static struct dirent dtmp;
  64.     static struct _dta    dtabuf;
  65.     struct _dta *olddta;
  66.     int r;
  67.  
  68.     strcpy(path, fullname);
  69.     if((tmp = strrchr(path, '\\'))) {
  70.         *tmp++ = 0;
  71.         _dos2unx(tmp, name);
  72.     }
  73.     else {
  74.         _dos2unx(path, name);
  75.         path[0] = 0;
  76.     }
  77.  
  78. /*
  79.  * search through the chain of open directories, 1 at a time
  80.  */
  81.     for (dir = __opendir_chain; dir; dir = dir->D_nxtdir) {
  82.         if (!strcmp(path, dir->D_path)) {
  83.             for (d = dir->D_list; d; d = d->d_next) {
  84.                 if (!strcmp(name,d->d_name) &&
  85.                     d->d_attribute != 0xff) {
  86.                     return d;
  87.                 }
  88.             }
  89.         }
  90.     }
  91.     d = &dtmp;
  92.     olddta = (struct _dta *)Fgetdta();
  93.     Fsetdta(&dtabuf);
  94.     r = Fsfirst(fullname, FA_SYSTEM|FA_HIDDEN|FA_DIR);
  95.     Fsetdta(olddta);
  96.     if (r < 0) {
  97.         errno = -r;
  98.         return NULL;
  99.     }
  100.     d->d_ino = __inode++;
  101.     d->d_time = dtabuf.dta_time;
  102.     d->d_date = dtabuf.dta_date;
  103.     d->d_attribute = dtabuf.dta_attribute;
  104.     d->d_size = dtabuf.dta_size;
  105.  
  106.     return d;
  107. }
  108.  
  109. static int
  110. _stat(_path, st)
  111.     const char    *_path;
  112.     struct stat    *st;
  113. {
  114.     int    rval, nval;
  115.     char    path[FILENAME_MAX];
  116.     char    *ext, drv;
  117.     int    fd;
  118.     short    magic;
  119.     struct dirent *d;
  120.     struct _device *device;
  121.  
  122.     if (!_path) {
  123.         errno = EFAULT;
  124.         return -1;
  125.     }
  126.  
  127. /*
  128.  * NOTE: the new _unx2dos gives a complete, canonical TOS pathname
  129.  * (i.e. stripped of . and .., and with a drive letter). It also returns
  130.  * some useful information about what the given filename was (e.g. symlink,
  131.  * or device)
  132.  */
  133.     nval = _unx2dos(_path, path);
  134.     if (nval == _NM_DEV) {
  135.         device = _dev_dosname(path);
  136.         st->st_mode = S_IFCHR | 0600;
  137.         st->st_attr = 0xfe;
  138.         st->st_ino = st->st_rdev = device->dev;
  139.         st->st_mtime = st->st_ctime = st->st_atime = 
  140.             time((time_t *)0) - 2;
  141.         st->st_dev = 0;
  142.     /* if _tDEV is on, /dev/console & CON: are the same file */
  143.         st->st_nlink = _tDEV ? 2 : 1;
  144.         st->st_uid = geteuid();
  145.         st->st_gid = getegid();
  146.         st->st_blksize = 1024;
  147.         return 0;
  148.     }
  149.  
  150.     /* Deal with the root directory of a logical drive */
  151.     if (path[0] == '\\' && path[1] == 0) {
  152.         drv = Dgetdrv() + 'A';
  153.         goto rootdir;
  154.     }
  155.  
  156.     if ( (drv = path[0]) && path[1] == ':' &&
  157.          (path[2] == 0 || (path[2] == '\\' && path[3] == 0)) ) {
  158. rootdir:
  159.         st->st_mode = S_IFDIR | 0755;
  160.         st->st_attr = FA_DIR;
  161.         st->st_ino = isupper(drv) ? drv - 'A' : drv - 'a';
  162.         st->st_mtime = st->st_ctime = st->st_atime = OLDDATE;
  163.         goto fill_dir;
  164.     }
  165.  
  166.     /* forbid wildcards in path names */
  167.     if (index(path, '*') || index(path, '?')) {
  168.         errno = ENOENT;
  169.         return -1;
  170.     }
  171.  
  172.     if (!(d = _do_stat(path))) {
  173.     /* errno was set by _do_stat */
  174.         if ((errno == ENOENT || errno == EPATH) && nval == _NM_LINK) {
  175.         /* here we have a symbolic link to a deleted file */
  176.             st->st_mode = S_IFLNK | 0644;
  177.             st->st_ino = ++__inode;
  178.             st->st_attr = 0xff;
  179.             st->st_mtime = st->st_ctime = st->st_atime = OLDDATE;
  180.             st->st_size = strlen(__link_to);
  181.             st->st_blocks = 1;
  182.             st->st_nlink = 1;
  183.             goto fill_rest;
  184.         }
  185.         return -1;
  186.     }
  187.     st->st_mtime = st->st_ctime = st->st_atime =
  188.         _unixtime(d->d_time, d->d_date);
  189.     st->st_ino = d->d_ino;
  190.     st->st_attr = d->d_attribute;
  191.     st->st_mode = 0644 | (d->d_attribute & FA_DIR ?
  192.                   S_IFDIR | 0111 : S_IFREG);
  193.     if (d->d_attribute & FA_RDONLY)
  194.         st->st_mode &= ~0222;    /* no write permission */
  195.     if (d->d_attribute & FA_HIDDEN)
  196.         st->st_mode &= ~0444;    /* no read permission */
  197.  
  198. /* check for a file with an executable extension */
  199.     ext = strrchr(_path, '.');
  200.     if (ext) {
  201.         if (!strcmp(ext, ".ttp") || !strcmp(ext, ".prg") ||
  202.             !strcmp(ext, ".tos") || !strcmp(ext, ".g") ||
  203.             !strcmp(ext, ".sh")     || !strcmp(ext, ".bat")) {
  204.             st->st_mode |= 0111;
  205.         }
  206.     }
  207.     if ( (st->st_mode & S_IFMT) == S_IFREG) {
  208.         if (_x_Bit_set_in_stat) {
  209.             if ((fd = Fopen(path,0)) < 0) {
  210.                 errno = -rval;
  211.                 return -1;
  212.             }
  213.             (void)Fread(fd,2,(char *)&magic);
  214.             (void)Fclose(fd);
  215.             if (magic == 0x601A) st->st_mode |= 0111;
  216.         }
  217.         st->st_size = d->d_size;
  218.         st->st_blocks = (d->d_size + 1023) / 1024;
  219.         st->st_nlink = 1; /* we dont have hard links */
  220.     } else {
  221. fill_dir:
  222.         st->st_size = 1024;
  223.         st->st_blocks = 1;
  224.         st->st_nlink = 2;    /* "foo" && "foo/.." */
  225.     }
  226.  
  227. fill_rest:
  228.     if ((drv = *path) && path[1] == ':')
  229.         st->st_dev = islower(drv) ? drv - 'a' : drv - 'A';
  230.     else
  231.         st->st_dev = Dgetdrv();
  232.     st->st_rdev = 0;
  233.     st->st_uid = geteuid();    /* the current user owns every file */
  234.     st->st_gid = getegid();
  235.     st->st_blksize = 1024;
  236.     return nval;
  237. }
  238.  
  239. int
  240. stat(path, st)
  241.     const char    *path;
  242.     struct stat    *st;
  243. {
  244.     return _stat(path, st) < 0 ? -1 : 0;
  245. }
  246.  
  247. #include <fcntl.h>
  248. #include <memory.h>
  249.  
  250. int fstat(fd, st)
  251. int fd;
  252. struct stat *st;
  253. {
  254.     int old;
  255.     int r;
  256.     struct _device *dev = _dev_fd(fd);
  257.     
  258.     if(dev)
  259.     {
  260.     char *devname = (char *)alloca(strlen(dev->unxnm) + 6L);
  261.     (void) strcpy(devname, "/dev/");
  262.     (void) strcat(devname, dev->unxnm);
  263.     return stat(devname, st);
  264.     }
  265.     
  266.     fd = __OPEN_INDEX(fd);
  267.     if((fd >= 0) && (fd < __NHANDLES))
  268.     {
  269.     if (__open_stat[fd].filename) {
  270.         /* we should turn off links, because the name we're going to give
  271.          * to 'stat' has already been _unx2dos'd
  272.          */
  273.         old = _lOK;
  274.         _lOK = 0;
  275.         r = stat(__open_stat[fd].filename, st);
  276.         _lOK = old;
  277.         return r;
  278.     } else {
  279.         _DOSTIME timestruct;
  280.         
  281.         /* the following code is stolen from Eric R. Smith */
  282.         r = Fdatime(×truct, fd, 0);
  283.         if (r < 0) {            /* assume TTY */
  284.         st->st_mode = S_IFCHR | 0600;
  285.         st->st_attr = 0;
  286.         st->st_mtime = st->st_ctime = st->st_atime =
  287.             time((time_t *)0) - 2;
  288.         st->st_size = 0;
  289.         } else {
  290.         long oldplace;
  291.         
  292.         st->st_mtime = st->st_atime = st->st_ctime =
  293.             _unixtime(timestruct.time,timestruct.date);
  294.         st->st_mode = S_IFREG | 0644;        /* this may be false */
  295.         st->st_attr = 0;            /* because this is */
  296.         
  297.         /* get current file location */
  298.         oldplace = Fseek(0L, fd, SEEK_CUR);
  299.         if (oldplace < 0) {        /* can't seek -- must be pipe */
  300.             st->st_mode = S_IFIFO | 0644;
  301.             st->st_size = 1024;
  302.         } else {
  303.             short magic;
  304.             r = Fseek(0L, fd, SEEK_END);    /* go to end of file */
  305.             st->st_size = r;
  306.             (void)Fseek(0L, fd, SEEK_SET);    /* go to start of file */
  307.             /* check for executable file */
  308.             if (_x_Bit_set_in_stat && 
  309.             Fread(fd, 2, (char *)&magic) == 2) {
  310.             if (magic == 0x601a || magic == 0x2321)
  311.                 st->st_mode |= 0111;
  312.             }
  313.             (void)Fseek(oldplace, fd, SEEK_SET);
  314.         }
  315.         }
  316.         
  317.         /* all this stuff is likely bogus as well. sigh. */
  318.         st->st_dev = Dgetdrv();
  319.         st->st_rdev = 0;
  320.         st->st_uid = getuid();
  321.         st->st_gid = getgid();
  322.         st->st_blksize = 1024;
  323.         /* note: most Unixes measure st_blocks in 512 byte units */
  324.         st->st_blocks = (st->st_size + 511) / 512;
  325.         st->st_ino = ++__inode;
  326.         st->st_nlink = 1;
  327.         return 0;
  328.         
  329.     }
  330.     }
  331.     errno = EBADF;
  332.     return -1;
  333. }
  334.  
  335. /*
  336.  * "stat" that doesn't follow symbolic links
  337.  * important exception: if _lAUTO is set and the link is an automatic
  338.  * link, follow it anyways. This allows automatic links to be aliases
  339.  * for real files (stat will correctly return the info about the
  340.  * automatic link if the real file has been deleted).
  341.  */
  342.  
  343. int
  344. lstat(_path, st)
  345.     const char *_path;
  346.     struct stat *st;
  347. {
  348.     int r;
  349.  
  350. /* _unx2dos returns _NM_LINK if the last path component was a symbolic link
  351.  * in this case, __link_name and __link_path are set to the name and path
  352.  * of the symbolic link file, __link_to to its contents, and __link_flags
  353.  * its flags.
  354.  */
  355.     r = _stat(_path, st);
  356.  
  357.     if (r < 0)
  358.         return r;
  359.  
  360.     if (r == _NM_LINK && !(__link_flags & SD_AUTO))
  361.     {
  362.         st->st_size = strlen(__link_to);
  363.         st->st_blocks = 1;
  364.         st->st_mode = ((st->st_mode & ~S_IFMT) | S_IFLNK);
  365.     }
  366.     return 0;
  367. }
  368.